﻿using System.Collections.Generic;
using System.Linq;
using SIG.Repository;

using System;
using SIG.Infrastructure.Logging;
using SIG.Infrastructure.Cache;
using System.Threading.Tasks;
using System.Threading;
using SIG.Model.Identity;

using SIG.Infrastructure.Configs;
using SIG.Infrastructure.Helper;
using SIG.Model.Enum;
using SIG.Resources.Admin;
using SIG.Infrastructure.Extensions;

namespace SIG.Service
{
    public class MenuService: EntityService<Menu>, IMenuService
    {
      
        private readonly IMenuRepository _menuRepository;
        private readonly ILoggingService _loggingService;
        private readonly ICacheService _cacheService;


        public MenuService( IMenuRepository menuRepository, ILoggingService loggingService, ICacheService cacheService)
            : base(menuRepository, cacheService, loggingService)
        {
         
            _menuRepository = menuRepository;
            _loggingService = loggingService;
            _cacheService = cacheService;
        
        }

        public List<Menu> GetFrontMenus(int categoryId)
        {
            var key = $"{EntityNames.Menu}_FrontMenu_{categoryId}";

            if (!SettingsManager.Menu.EnableCaching)
                return _menuRepository.GetFilteredElements((m => m.CategoryId == categoryId && m.ParentId == null), (m => m.ChildMenus)).ToList();


            if (_cacheService.IsSet(key))
                return (List<Menu>)_cacheService.Get(key);


            List<Menu> menus = _menuRepository.GetFilteredElements((m => m.CategoryId == categoryId && m.ParentId == null), (m => m.ChildMenus)).ToList();
            _cacheService.Set(key, menus, SettingsManager.Menu.CacheDuration);

            return menus;

        }

        public Menu CreateAndSort(Menu menu)
        {
            var menuList = _menuRepository.GetFilteredElements(m => m.CategoryId == menu.CategoryId).OrderBy(m=>m.Importance).ToList();
         
                var parentMenu = menuList.Where(m => m.Id == menu.ParentId).FirstOrDefault();
                if (parentMenu != null)
                {
                    int index = menuList.IndexOf(parentMenu);

                    menu.Importance = index + 1;
                    int i = 1;
                    foreach (var childItem in menu.ChildMenus)
                    {
                        childItem.Importance = menu.Importance + i;
                        i++;
                    }

                    int toIndex = index + 1 + menu.ChildMenus.Count();

                    //重新排序
                    var menus = _menuRepository.GetFilteredElements(m => m.CategoryId == menu.CategoryId).OrderBy(m => m.Importance);
                    int j = 1;
                    foreach (var item in menus)
                    {
                        if (j > index)
                        {
                            item.Importance = toIndex + j;
                            _menuRepository.SetModified(item);
                        }
                        j++;
                    }
                }
               
            
            
            _menuRepository.Add(menu);
            _menuRepository.UnitOfWork.Commit();

            return menu;
        }
        

        public void ResetSort(int categoryId)
        {
            var menuList = _menuRepository.GetFilteredElements(m => m.CategoryId == categoryId && m.ParentId == null,m=>m.ChildMenus).OrderBy(m => m.Importance);
            var list = menuList.SelectDeep<Menu>(m=>m.ChildMenus.OrderBy(g=>g.Importance));

            int i = 0;
            foreach (var item in list)
            {
                item.Importance = i;              
                _menuRepository.SetModified(item);
                i ++;
            }
            
            _menuRepository.UnitOfWork.Commit();
            _cacheService.Invalidate(EntityNames.Menu);
           // return menu;
        }

        //
        public int UpMoveMenu(int id)
        {
            Menu vMenu = GetById(id);
            var menuList = _menuRepository.GetFilteredElements(m => m.CategoryId == vMenu.CategoryId).OrderBy(m=>m.Importance); 

            Menu prevMenu = menuList.Where(m => m.ParentId == vMenu.ParentId &&
                m.Importance < vMenu.Importance).OrderByDescending(m => m.Importance).FirstOrDefault();

            
            if (prevMenu == null)
            {
               // 已经在第一位
                return 0;
            }

            vMenu.Importance = prevMenu.Importance;
            _menuRepository.SetModified(vMenu);
            var childMenus = menuList.Where(m => m.ParentId == vMenu.Id).OrderBy(m=>m.Importance);
            int i = 1;
            foreach(var child in childMenus)
            {
                child.Importance = vMenu.Importance + i;
                i++;
                _menuRepository.SetModified(child);
            }

            prevMenu.Importance = vMenu.Importance + childMenus.Count() + 1;
            _menuRepository.SetModified(prevMenu);
            var childPrevMenus = menuList.Where(m => m.ParentId == prevMenu.Id).OrderBy(m => m.Importance);
            int j = 1;
            foreach (var child in childPrevMenus)
            {
                child.Importance = vMenu.Importance + j;
                j++;
                _menuRepository.SetModified(child);
            }

            _menuRepository.UnitOfWork.Commit();
            _cacheService.Invalidate(EntityNames.Menu);
            return 1;
        }

        public int DownMoveMenu(int id)
        {
            Menu vMenu = GetById(id);

            var menuList = _menuRepository.GetFilteredElements(m => m.CategoryId == vMenu.CategoryId).OrderBy(m => m.Importance);

            Menu nextMenu = menuList.Where(m => m.ParentId == vMenu.ParentId &&
                m.Importance > vMenu.Importance).OrderBy(m => m.Importance).FirstOrDefault();


            if (nextMenu == null)
            {
                // 已经在第一位
                return 0;
            }


            nextMenu.Importance = vMenu.Importance;
            _menuRepository.SetModified(nextMenu);
            var childPrevMenus = menuList.Where(m => m.ParentId == nextMenu.Id).OrderBy(m => m.Importance);
            int j = 1;
            foreach (var child in childPrevMenus)
            {
                child.Importance = vMenu.Importance + j;
                j++;
                _menuRepository.SetModified(child);
            }


            vMenu.Importance = nextMenu.Importance + childPrevMenus.Count() + 1;
            _menuRepository.SetModified(vMenu);
            var childMenus = menuList.Where(m => m.ParentId == vMenu.Id).OrderBy(m => m.Importance);
            int i = 1;
            foreach (var child in childMenus)
            {
                child.Importance = vMenu.Importance + i;
                i++;
                _menuRepository.SetModified(child);
            }
            
            _menuRepository.UnitOfWork.Commit();
            _cacheService.Invalidate(EntityNames.Menu);
            return 1;
        }


        public Menu GetMenuWithChildMenus(int Id)
        {
            var menu = _menuRepository.GetFirstOrDefault(m => m.Id == Id, m => m.ChildMenus);
            return menu;
        }
        public List<Menu> GetShowMenus(int categoryId)
        {
            var key = $"{EntityNames.Menu}s_Show_{categoryId}";

            if (!SettingsManager.Menu.EnableCaching)
                return  _menuRepository.GetFilteredElements(m => m.CategoryId == categoryId  && (m.MenuType == MenuType.NOLINK || m.MenuType == MenuType.PAGE)).OrderBy(m=>m.Importance).ToList();

            if (_cacheService.IsSet(key))
                return (List<Menu>)_cacheService.Get(key);

            var menus = _menuRepository.GetFilteredElements(m => m.CategoryId == categoryId  && (m.MenuType == MenuType.NOLINK || m.MenuType == MenuType.PAGE)).OrderBy(m => m.Importance).ToList();
            _cacheService.Set(key, menus, SettingsManager.Menu.CacheDuration);

            return menus;

        }
        public async Task<IEnumerable<Menu>> GetMenus(int categoryId, CancellationToken cancellationToken = default(CancellationToken))
        {           
            return await _menuRepository.FindByAsync<int>((m=>m.CategoryId == categoryId && m.ParentId == null), m=>m.Importance, true, cancellationToken, (m=>m.ChildMenus)); 
        }

        public List<Menu> GetFaltMenus(int categoryId)
        {
            var key = $"{EntityNames.Menu}s_FALT_{categoryId}";

            if (!SettingsManager.Menu.EnableCaching)
                return FaltMenus(categoryId);


            if (_cacheService.IsSet(key))
                return (List<Menu>)_cacheService.Get(key);


            List<Menu> menus = FaltMenus(categoryId);
            _cacheService.Set(key, menus, SettingsManager.Menu.CacheDuration);

            return menus;
            // return await _menuRepository.FindByAsync<int>((m => m.CategoryId == categoryId), m => m.Importance, false, cancellationToken, (m => m.ChildMenus));
        }
        private List<Menu> FaltMenus(int categoryId)
        {
            List<Menu> menus;
            var orgMenus = _menuRepository.GetFilteredElements((m => m.CategoryId == categoryId && m.ParentId == null), (m => m.ChildMenus));

            Menu vMenu = orgMenus.FirstOrDefault();
            //  var dto = _mapper.Map<MenuVM>(vMenu);

            menus = vMenu.ChildMenus.Where(m => m.Active).OrderBy(m => m.Importance).ToList();
            vMenu.ChildMenus.Clear();
            menus.Insert(0, vMenu);
            return menus;
        }




        public List<Menu> CurrenMenuCrumbs(int categoryId)
        {
            string area = Site.CurrentArea(), controller = Site.CurrentController(), action = Site.CurrentAction();
          
            var rource = GetShowMenus(categoryId);
            List<Menu> menus = new List<Menu>();
            
            Menu vMenu = rource.FirstOrDefault(m => area.Equals(m.Area, StringComparison.OrdinalIgnoreCase)
            && controller.Equals(m.Controller, StringComparison.OrdinalIgnoreCase)
            && action.Equals(m.Action, StringComparison.OrdinalIgnoreCase));

            if (vMenu != null)
                RecursiveLoad(vMenu, menus);            
                 
            return menus;
        }

        /// <summary>
        /// 递归获取父项
        /// </summary>
        /// <param name="vMenu"></param>
        /// <param name="Parents"></param>
        private void RecursiveLoad(Menu vMenu, List<Menu> Parents)
        {
            Parents.Insert(0, vMenu);
            if (vMenu.ParentId != null)
            {
                var rource = GetShowMenus(vMenu.CategoryId);
                Menu parentMenu = rource.FirstOrDefault(m => m.Id == vMenu.ParentId);
                if(parentMenu!=null)
                    RecursiveLoad(vMenu.ParentMenu, Parents);
            }
        }

        /// <summary>
        /// 获取需要高亮的菜单ID
        /// </summary>
        /// <returns></returns>
        public Menu GetCurrenMenu()
        {
            string area = Site.CurrentArea(), controller = Site.CurrentController(), action = Site.CurrentAction();

            var menus = GetAllMenusByCategoryId(SettingsManager.Menu.BackMenuCId);

            if (menus == null)
                return null;

            Menu vMenu = menus.FirstOrDefault(m=> area.Equals( m.Area,StringComparison.OrdinalIgnoreCase)
            && controller.Equals( m.Controller, StringComparison.OrdinalIgnoreCase) 
            && action.Equals( m.Action, StringComparison.OrdinalIgnoreCase));
            

            if (vMenu == null)
                return null;

            if (vMenu.Active||vMenu.MenuType== MenuType.PAGE)
                return vMenu;
          
            return  RecursiveLoadMenu(vMenu.ParentId);


        }
        private Menu RecursiveLoadMenu(int? parentId)
        {
            var menus = GetAllMenusByCategoryId(SettingsManager.Menu.BackMenuCId);

            Menu vMenu = menus.Where(m => m.ParentId == parentId && m.MenuType == MenuType.PAGE
           ).FirstOrDefault();

            if (vMenu.ParentMenu != null && (vMenu.ParentMenu.MenuType!=MenuType.PAGE || !vMenu.ParentMenu.Active))
            {
               return RecursiveLoadMenu(vMenu.ParentId);
            }
            return vMenu.ParentMenu;
        }

        public List<Menu> GetAllMenusByCategoryId(int categoryId)
        {
            var key = $"{EntityNames.Menu}s_FaltAll_{categoryId}";

            List<Menu> menus;

            if (SettingsManager.Menu.EnableCaching)
            {
                if (_cacheService.IsSet(key))
                {
                    menus = (List<Menu>)_cacheService.Get(key);

                }
                else
                {
                    menus = _menuRepository.GetFilteredElements(m => m.CategoryId == categoryId).ToList();
                    _cacheService.Set(key, menus, SettingsManager.Menu.CacheDuration);
                }
            }
            else
            {
                menus = _menuRepository.GetFilteredElements(m => m.CategoryId == categoryId).ToList();
            }

            return menus;
        }

        public List<Menu> GetMenusByCategoryId(int categoryId)
        {
            var key = $"{EntityNames.Menu}s_{categoryId}";

            List<Menu> menus;

            if (SettingsManager.Menu.EnableCaching)
            {
                if (_cacheService.IsSet(key))
                {
                    menus = (List<Menu>)_cacheService.Get(key);

                }
                else
                {
                    menus = _menuRepository.GetFilteredElements((m => m.CategoryId == categoryId && m.ParentId == null), (m => m.ChildMenus)).ToList();
                    _cacheService.Set(key, menus, SettingsManager.Menu.CacheDuration);
                }
            }
            else
            {
                menus = _menuRepository.GetFilteredElements((m => m.CategoryId == categoryId && m.ParentId == null), (m => m.ChildMenus)).ToList();
            }
            
            return menus;
        }      


    }
}
